import pygame
from pygame.locals import *
from pygame.color import *
import pymunk as pm
from pymunk import Vec2d
import math, sys, random

HERO = 1
BOXES = 2
rem_obj = None
button_down = False
destruct_speed = 500

def begin(space, arbiter, args, kwargs):
    global rem_obj, button_down
    (a, b) = arbiter.shapes
    speed = b.body.velocity.get_length()
    if not(button_down) and speed > destruct_speed:
        rem_obj = a
    return True 

def flipyv(p):
    """Small hack to convert pymunk to pygame coordinates"""
    return int(p.x), int(-p.y+600)

def create_poly(points, mass = 5.0, pos = (0,0)):
    global space
    moment = pm.moment_for_poly(mass,points, Vec2d(0,0))    
    #moment = 1000
    body = pm.Body(mass, moment)
    body.position = Vec2d(pos)       
    
    shape = pm.Poly(body, points, Vec2d(0,0))
#    shape.friction = 0.5
    shape.elasticity = 0.5
    shape.collision_type = BOXES 
    space.add(body, shape)
    return shape
 
def create_box(pos, size = 10, mass = 5.0):
    box_points = map(Vec2d, [(-size, -size), (-size, size), (size,size), (size, -size)])
    return create_poly(box_points, mass = mass, pos = pos)
 
def draw_poly(poly):
    global screen
    body = poly.body
    ps = poly.get_points()
    ps.append(ps[0])
    ps = map(flipyv, ps)
    color = THECOLORS["green"]
    pygame.draw.lines(screen, color, False, ps)
          
pygame.init()
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
running = True

### Physics stuff
pm.init_pymunk()
space = pm.Space()
space.gravity = (0.0, -100.0)

space.resize_static_hash()
space.resize_active_hash()

## Balls
balls = []
   
### walls
static_body = pm.Body(pm.inf, pm.inf)
static_lines = [pm.Segment(static_body, (0.0, 600.0), (0.0, 0.0), 0.0)
                ,pm.Segment(static_body, (0.0, 0.0), (600.0, 0.0), 0.0)
                ,pm.Segment(static_body, (600.0, 0.0), (600.0, 600.0), 0.0)
                ,pm.Segment(static_body, (0.0, 600.0), (600.0, 600.0), 0.0)
                ]  
for line in static_lines:
    line.elasticity = 1
space.add_static(static_lines)

mass = 10
radius = 10
inertia = pm.moment_for_circle(mass, 0, radius, (0,0))
body = pm.Body(mass, inertia)
x = random.randint(115,350)
body.position = x, 400
ball = pm.Circle(body, radius, (0,0))
ball.collision_type = HERO
ball.elasticity = 1
space.add(body, ball)

sbb = pm.Body(pm.inf, pm.inf)
sbb.position = (300, 300) 

rot_center = pm.PinJoint(body, sbb, (0, 0), (5, 5)) 
rot_center.distance = 2*radius

boxes = []
for i in xrange(20):
    boxes.append(create_box((500, 600-i * 40), 40))

space.add_collision_handler(HERO, BOXES, begin, None, None, None, None, None)

#ticks_to_next_ball = 10

while running:
    for event in pygame.event.get():
        if event.type == QUIT:
            running = False
        elif event.type == KEYDOWN and event.key == K_ESCAPE:
            running = False
        elif event.type == MOUSEBUTTONDOWN:
            sbb.position = flipyv(Vec2d(event.pos))
            space.add(rot_center)
            print "mouse down"
            button_down = True
        elif event.type == MOUSEBUTTONUP:
            space.remove(rot_center)
            print "mouse relased"
            button_down = False
            
    ### Clear screen
    screen.fill(THECOLORS["white"])
    
    p = flipyv(ball.body.position)
    pygame.draw.circle(screen, THECOLORS["blue"], p, int(ball.radius), 2)

    p = flipyv(sbb.position)
    pygame.draw.circle(screen, THECOLORS["red"], p, 5, 2)

    for box in boxes:
        draw_poly(box)

    for line in static_lines:
        body = line.body
        pv1 = body.position + line.a.rotated(body.angle)
        pv2 = body.position + line.b.rotated(body.angle)
        p1 = flipyv(pv1)
        p2 = flipyv(pv2)
        pygame.draw.lines(screen, THECOLORS["lightgray"], False, [p1,p2])
        
    ### Update physics
    dt = 1.0/60.0
    space.step(dt)
    if rem_obj:
        space.remove(rem_obj)
        boxes.remove(rem_obj)        
        rem_obj = None

    #limit the velocity
    vlim = 500 #caliculated based on trial and error
    if ball.body.velocity.x > vlim:
        ball.body.velocity.x = vlim 
    elif ball.body.velocity.x < -vlim:
        ball.body.velocity.x = -vlim
    if ball.body.velocity.y > vlim:
        ball.body.velocity.y = vlim
    elif ball.body.velocity.y < -vlim:
        ball.body.velocity.y = -vlim
    ### Flip screen
    pygame.display.flip()
    clock.tick(50)
    pygame.display.set_caption("fps: " + str(clock.get_fps()))
